# -*-  coding:utf-8  -*-
import json

import requests
from  dbmysql  import db_mysql
import  time
import smtplib #核心包
from email.mime.text import MIMEText#以文本的形式进行写入
from  email.mime.multipart import MIMEMultipart#带附件的发送方式
import sys
sys.path.append('D:\ceshi_ruanjian\pychram_sq_work\c22035_git')


'''研究 在做接口测试的时候   发起方式都有那些  post  put  get  delete '''
'''封装请求方式'''
def  getRequest(url,method,data = None,header = None,cookies = None, Content_Type = None):
    #开始判断
    if method == 'get':
        res = requests.get(url = url , params= data , headers=header , cookies= cookies)
    elif method == 'post' :
        #判断是不是json格式
        if Content_Type == 'application/json':
            res = requests.post(url = url ,json= data,headers=header , cookies= cookies)
            print('post-json')
        else:
            res = requests.post(url=url, data=data, headers=header, cookies=cookies)
            print('post-data')
    elif method == 'delete':
        res = requests.delete(url=url, params=data, headers=header, cookies=cookies)
    elif method == 'put' :
        #判断是不是json格式
        if Content_Type == 'application/json':
            res = requests.put(url = url ,json= data,headers=header , cookies= cookies)
        else:
            res = requests.put(url=url, data=data, headers=header, cookies=cookies)
    else:
        print('其他发起方式没有封装')
        return 'None'
    #把结果进行返回
    return  res

'''通过传入的参数返回登录装填后的信息'''
def getCookie(pre_fields):
    url = 'http://gc.ftgyun.top/bus/login/in'
    data = {"account": "admin", "password": '123456'}
    res = getRequest(url=url, data=data,method='post')
    return str(res.cookies.get(pre_fields))

#实例化dbMysql的类
def  get_db():
    return  db_mysql.db_mysql(host='127.0.0.1', user='root', password='123456789', db='jk_api_test')

'''根据app字段查询全部内容'''
def  getQuery(app):
    #准备sql语句
    sql = "select  * from  jk_test where app = '{}'".format(app)
    #调用db连接下的方法
    tuples = get_db().getQuery(sql)
    return tuples

'''通过id查询一条数据  主要服务前置测试用例'''
def getQueryOne(case_id):
    #准备sqly
    sql = "select  * from  jk_test where id = '{}'".format(case_id)
    # 调用db连接下的方法
    tuples = get_db().getQuery(sql)
    return tuples

'''通过case_id进行修改表中数据'''
def get_update_case_id(response,passs,case_id):
    update_time = str(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
    print(update_time)
    #准备 sql语句
    sql = "update  jk_test set response = '{0}',update_time = '{1}' ,pass = '{2}' where  id = '{3}'".format(response,update_time,passs,case_id)
    print(sql)
    index = get_db().getDML(sql)
    return index

'''自行模拟断言'''
def get_assertResponse(case,res):
    #表中两个参数是需要咱们进行使用   assert_type  --  code   text    expect_result
    assert_type = case['assert_type']# 断言方式  数据库返回的结果集   元组的格式   通过取值 付给变量
    expect_result = case['expect_result']#预期结果
    if  assert_type != None  and  str(assert_type) == 'code':#assert_type  当前对象不为空 并保证 值是code
        #开始比较预期结果和实际结果
        if  str(expect_result)  == str(res):
            is_pass = True
            print('测试用例通过')
        else:
            is_pass = False
            print('测试用例不通过')
    elif assert_type != None  and  str(assert_type) == 'in':
        # 开始比较预期结果和实际结果
        if str(expect_result)  in str(res):
            is_pass = True
            print('测试用例通过')
        else:
            is_pass = False
            print('测试用例不通过')
    elif assert_type != None  and  str(assert_type) == 'equal':
        # 开始比较预期结果和实际结果
        if str(expect_result)  == str(res):
            is_pass = True
            print('测试用例通过')
        else:
            is_pass = False
            print('测试用例不通过')
    else:
        is_pass = False
        print('测试用例不通过')
    return  is_pass

'''测试用例的执行   查询的结果'''
def  get_runCase(case):
        #没有前置测试用例执行的测试用例
        run  = case['run']
        method = case['method']
        #查看当前测试用例是不是需要执行
        if  str(run) == 'yes':
            #开始执行内容
            url = case['url']#请求路径
            #判断请求头 有没有值
            if  case['headers'] != None:
                headers = json.loads(case['headers'])  # 请求头准备
            else:
                headers = None
            # 先进行判定  有没有前置测试用例   前置测试用例判定都是  缓存值
            pre_case_id = case['pre_case_id']  # 把前置测试用的id  取出来    用于判定 这个测试用例需不需要执行
            if int(pre_case_id) > -1:  # pre_case_id  值 大于 -1  代表有前置测试用例
                # 先通过 前置测试用例的编号  查询数据库内容    一条测试案例
                qian_case = getQueryOne(pre_case_id)
                #调用返回的前置测试用例的返回值
                pre_fields = case['pre_fields']
                cookie = getCookie(pre_fields)
                cookies = {pre_fields : cookie}#pre_fields字段装的是
            else:
                cookies = None#没有前置测试用   代表  cookies  就是空值
            #判定一下 headers 中有没有  Content-type  这个参数
            if  case['msg'] !=  "None":#   Content-Type  在  headers 中  取出来使用   不在  直接赋空值
                Content_Type = case['msg']
            else:
                Content_Type = None
            #发起的参数
            #判断   当前  request_body 有没有值   有值 长度一定大于 0
            if case['request_body']  !=  None:
                data = json.loads(case['request_body'])#把字符串转换成json格式   json格式在python中就是字典格式   要求:在填写的时候必须是双引号
                # 加入判定   判断你当前这个接口中有没有数据不能重复的字段
                request_body_repeat = str(case['request_body_repeat'])
                if request_body_repeat != 'None':  # 只有这里面有值的时候才进行判定
                    # 把字符串转换成列表
                    rbr = request_body_repeat.split(',')  # 通过逗号的截取方式 把 里面所有的值变成列表   循环列表中的内容  去替换解析好的字典内容
                    print(rbr)
                    # 生成时间戳
                    new_time = str(time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime()))
                    for i in rbr:  # 循环把值修改掉
                        data[i] = str(data[i]) + new_time  # 同等与   data['account'] = str(data[account]) + new_time
                    print("data----------" + str(data))
            else:
                data = None
            #参数准备完成  调用request方法   对接口发起请求
            res = getRequest(url = url,method = method,data = data,header = headers,cookies = cookies,Content_Type=Content_Type)
            #通过   assert_type这个字段的内容  来判定咱们要选择的断言方式
            assert_type =  case['assert_type']
            #开始判断
            if str(assert_type)  == 'code':
                #咱们的实际结果   返回值就是 code
                shi = res.status_code   #status_code  返回的是 int类型   没办法获取长度的
            else :#只要不是  code   返回的结果都是  text文本格式
                shi = res.text
                # 判断  65534  200
                if len(shi) > 500:
                    shi = res.text[0:501]
            #开始断言
            is_pass = get_assertResponse(case,shi)
            #调用  修改语句  把执行的结果存进数据库
            case_id = case['id']
            index = get_update_case_id(shi,is_pass,case_id)
            return index

'''发送邮件'''
def  getEmail(app):
    neirong = get_neirong(app)
    #准备服务器地址
    smtpserver = 'smtp.163.com'
    #准备发送邮箱的账号和密码
    username = 'zcd18904815180@163.com'
    password = 'BRTQIWSEZPPBIFZR'
    #接收邮箱
    fasong = 'zcd18904815180@163.com'
    jieshou = ['18904815180@163.com']
    #准备主题
    zhuti = str(time.strftime('%Y_%m_%d_%H_%M_%S',time.localtime()))+'测试报告'
    #构建发送内容
    mms = MIMEMultipart()#带附件的形式发送
    mms.attach(MIMEText(neirong,'html','utf-8'))
    mms['From'] = fasong
    mms['To'] = ','.join(jieshou)
    mms['Subject'] = zhuti
    #开始发送
    smtp = smtplib.SMTP_SSL(smtpserver,465)#两个参数   服务器地址  和   服务器端口号  465
    #向服务器表明身份
    smtp.helo()
    #等待服务器返回结果
    smtp.ehlo()
    #请输入服务的用户名和密码
    smtp.login(user=username,password=password)
    #发送
    print('开始发送')
    smtp.sendmail(fasong,jieshou,mms.as_string())
    print('发送完成')

'''邮件内容'''
def  get_neirong(app):
    case = getQuery(app)  # 重新查询数据库 保证数据是最新的
    temp = ""
    # 循环数据库所有内容 把 数据库内容累计进入字符串
    for c in case:
        temp += "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>".format(c['id'], c['module'],
                                                                                               c['title'], c['pass'],
                                                                                               c['update_time'])
    #内容
    neirong = '<html>' \
              '<body>' \
              '<h4>{0}接口测试报告</h4>' \
              '<h4>测试报告生成时间{1}</h4>' \
              '<table  border = "1">' \
              '<tr><th>用例编号</th>' \
              '<th>模块</th>' \
              '<th>标题</th>' \
              '<th>是否通过</th>' \
              '<th>运行时间</th>' \
              '</tr>' \
              '{2}' \
              '</table>' \
              '</body></html>'.format(app,str(time.strftime('%Y_%m_%d_%H_%M_%S',time.localtime())),temp)
    #把内容中的添加进入
    return  neirong

'''执行全部测试用例  app  代表的'''
def  runAllCase(app):
    cases = getQuery(app)
    print(cases)
    # 开始循环里面的内容  分别调用  get_runCase这个方法
    for c in cases:
        index = get_runCase(c)
    #调用测试报告   发送邮件
    getEmail(app)


if __name__ == '__main__':
    #调用总执行文件
    #runAllCase('公车管理系统')
    '''
    架构  request  +  自研架构  
    1.封装  requests  这个方法 方法名字 get_Request()
    2.封装断言方法   封装了 三种断言方式    code   in  equal
    3.链接数据   通过设计数据库表结构  把一条接口测试案例所需要的数据都放进入数据库中 
      封装三个方法   查询数据库全部信息    通过用例编号查询一条数据（这个方法主要用于前置测试用例执行）  
      修改表中数据（更新测试用例执行后的结构）
    4.封装单条测试用例执行  以上封装的方法联合起来使用   主要是就从数据库中取出数据  调用get_request方法执行结果
      把结果存放进数据库中    用于测试报告读取
    5.封装整体运行方法  整体运行完成  发送测试报告
    6.针对表中数据的录入和修改  使用Flask架构封装前台方法
    更新：  只要公司有对应的需求   更改源代码  让架构更加完善
    '''






